package weixin.util;

import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.PropertyUtils;
import org.jdom.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import weixin.pojo.Message;
import weixin.pojo.TextMessage;

public class PojoUtil {
	private static Logger logger = LoggerFactory.getLogger(PojoUtil.class);

	@SuppressWarnings("unchecked")
	public static Message parseMessage(InputStream in) {
		Message msg = null;
		Map<String, String> propertyMap = ConvertUtil.getMessagePropertyMap(in);
		String msgType = propertyMap.get(Message.MsgType_Element);
		msg = getMessageByType(msgType);
		if (msg != null) {
			Iterator<Entry<String, String>> pit = propertyMap.entrySet()
					.iterator();
			while (pit.hasNext()) {
				Entry<String, String> entry = pit.next();
				String propertyName = entry.getKey();
				if (!propertyName.equals(Message.MsgType_Element)) {
					String propertyValue = entry.getValue();
					try {
						PropertyUtils.setProperty(msg,
								StringUtil.lowerFirstLetter(propertyName),
								propertyValue);
					} catch (IllegalAccessException e) {
						e.printStackTrace();
						logger.error("could not set the message property: "
								+ propertyName
								+ "! for the property value is: "
								+ propertyValue);
					} catch (InvocationTargetException e) {
						e.printStackTrace();
						logger.error("could not set the message property: "
								+ propertyName
								+ "! for the property value is: "
								+ propertyValue);
					} catch (NoSuchMethodException e) {
						e.printStackTrace();
						logger.error("could not set the message property: "
								+ propertyName
								+ "! for the property value is: "
								+ propertyValue);
					}
				}
			}
		}
		return msg;
	}

	public static String transformMessage(Message msg) {
		StringBuilder sb = new StringBuilder(100);
		sb.append("<xml>");
		if (msg != null) {
			PropertyDescriptor[] propertyDescriptors = PropertyUtils
					.getPropertyDescriptors(msg);
			if (propertyDescriptors != null && propertyDescriptors.length > 0) {
				for (PropertyDescriptor pd : propertyDescriptors) {
					String name = pd.getName();
					if ("class".equals(name)
							&& pd.getPropertyType().getName()
									.equals("java.lang.Class")) {
						continue;
					}
					Method methodGet = pd.getReadMethod();
					if (methodGet != null) {
						Object retVal = null;
						try {
							retVal = methodGet.invoke(msg);
						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InvocationTargetException e) {
							e.printStackTrace();
						}
						if (retVal != null) {
							String eName = StringUtil.upperFirstLetter(name);
							sb.append("<" + eName + ">");
							if (name.equals(Message.CreateTime_Property)) {
								sb.append(retVal);
							} else {
								sb.append("<![CDATA[" + retVal + "]]>");
							}
							sb.append("</" + eName + ">");
						}
					}
				}
			}
		}
		sb.append("</xml>");
		return sb.toString();
	}

	public static Message getMessageByType(String msgType) {
		Message msg = null;
		if (msgType != null) {
			if (msgType.equals(Message.Text_Type)) {
				msg = new TextMessage();
			} else {
				logger.error("could not find the message type!");
			}
		}
		return msg;
	}

	public static void main(String[] args) throws JDOMException, IOException {
		String msg = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId></xml>";
		Message message = PojoUtil.parseMessage(new ByteArrayInputStream(msg
				.getBytes()));
		System.out.println(message.getMsgType());
		System.out.println(PojoUtil.transformMessage(message));
	}
}
